home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 Extra Demos / Circular Scrolling / Circular Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-06  |  27.1 KB  |  960 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // Scrolling Demo.c
  3. //
  4. // By Vern Jensen. Created in August of 1995
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11. #include <BlitPixieScaled.h>
  12.  
  13. #include "SWApplication.h"
  14. #include "Circular Demo.h"
  15.  
  16.  
  17. #define    kFullScreenWindow            true        // 640x480 instead of 512x384
  18. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  19. #define    kInterlacedMode                false        // NOT compatible with the zoom out intro!
  20. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  21. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  22.  
  23. #define kDoZoomOutIntro                true        // turn this off if the scaling intro is too slow
  24.  
  25. #define    kScrollSpeed                10            // keyboard scrolling speed
  26. #define kNumSprites                    100            // number of balls
  27. #define kMaxSpriteMoveDelta            4            // maximum vert & horiz speed of balls
  28.  
  29.  
  30. #define    kSpriteMoveDelta            20            // Try 5, 10, 20, or 40
  31. #define kDiamondSpace                8            // How far apart the diamonds are spaced
  32.                                                 // (try 1!)
  33.  
  34. #define kSpriteMoveDistance            80            // How far the sprite can move from
  35.                                                 // the center of the screen, in pixels.
  36.                                                 // Try making this value higher!
  37.  
  38.     // Number of ticks to wait before changing tile image; 0 = change every frame
  39. #define kDiamondFrameRate            8            // How often diamond tiles change frames
  40. #define kWallFrameRate                120            // How often wall changes frames
  41.  
  42. #define kBWPictResIDOffset            100
  43. #define kTileWidth                    40
  44. #define kTileHeight                    40
  45. #define kTileMapRows                96            // This will create a virtual circular world
  46. #define kTileMapCols                144            // whose bounds are evenly divisible by 640x480
  47.  
  48. #define kStartRow                    5            // Starting position of sprite
  49. #define kStartCol                    5            // in tile col and row
  50.  
  51.  
  52. #define    kLeftArrowKey                0x7B
  53. #define    kRightArrowKey                0x7C
  54. #define    kDownArrowKey                0x7D
  55. #define    kUpArrowKey                    0x7E
  56.  
  57. #define    kLeftKeyPad                    0x56
  58. #define    kRightKeyPad                0x58
  59. #define    kDownKeyPad                    0x54
  60. #define    kUpKeyPad                    0x5B
  61.  
  62. #define kEscKey                        0x35
  63. #define kPlusKey                    0x18
  64. #define kMinusKey                    0x1B
  65. #define kReturnKey                    0x24
  66.  
  67.  
  68. #define kNoKey                        0
  69. #define kLeftKey                    1
  70. #define kUpKey                        2
  71. #define kRightKey                    3
  72. #define kDownKey                    4
  73.  
  74.  
  75. enum tileIDs
  76. {
  77.     kWallTile,
  78.     kLastWallTile,
  79.     kGrassTile,
  80.     kBlackTile,
  81.     kDiamondTile,
  82.     kDiamondTile2,
  83.     kLastDiamondTile,
  84.     
  85.     kTunnelTile1,
  86.     kTunnelTile2,
  87.     kTunnelTile3,
  88.     kTunnelTile4,
  89.     kTunnelTile5,
  90.     kTunnelTile6,
  91.     kWireTile1,
  92.     kWireTile2,
  93.     
  94.     kMaxNumTiles
  95. };
  96.  
  97.  
  98.  
  99. /***********/
  100. /* Globals */
  101. /***********/
  102.  
  103. SpriteWorldPtr        gSpriteWorldP;
  104. SpriteLayerPtr        gBallSpriteLayerP, gTopSpriteLayerP, gBottomSpriteLayerP, gMeterSpriteLayerP;
  105. TileMapStructPtr    gTileMapStructP;
  106. TileMapPtr            gTileMap;
  107. SpritePtr            gSimpleSpriteP, gDiamondMeterSpriteP;
  108. SpritePtr            gSpriteArray[kNumSprites];
  109. DrawProcPtr            gSpriteDrawProc, gScreenDrawProc;
  110. DoubleDrawProcPtr    gDoubleRectDrawProc;
  111. WindowPtr            gWindowP;
  112. Rect                gScreenMidRect;
  113. short                gScaledWidth, gScaledHeight, gOriginalWidth, gOriginalHeight;
  114.  
  115. long                gNumDiamondsInMap = 0;    // Number of diamonds in the TileMap
  116. long                gNumDiamonds = 0;        // Number of diamonds sprite has collected
  117.  
  118. struct moveKeys        // Keeps track of which keys are up and which are down
  119. {
  120.     Boolean    up;
  121.     Boolean    right;
  122.     Boolean    down;
  123.     Boolean    left;
  124. } gScrollKeys, gBallKeys;
  125.  
  126. Boolean        gPlusKeyIsDown = 0, gMinusKeyIsDown = 0, gReturnKeyIsDown = 0;
  127.  
  128.  
  129.  
  130. ///--------------------------------------------------------------------------------------
  131. // Main
  132. ///--------------------------------------------------------------------------------------
  133.  
  134. void    main( void )
  135. {
  136.     Initialize(kNumberOfMoreMastersCalls);
  137.  
  138.     if (SWHasSystem7())
  139.     {
  140.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  141.         SetCursor(*GetCursor(watchCursor));
  142.         
  143.         CreateSpriteWorld();
  144.         SetUpTiling();
  145.         CreateMainBallSprite();
  146.         CreateBallSprites();
  147.         CreateDiamondMeterSprite();
  148.         
  149.         SetCursor(&qd.arrow);
  150.         HideCursor();
  151.         
  152.         SetUpAnimation();
  153.         RunAnimation();
  154.         ShutDown();
  155.         
  156.         RestoreEventMask();    // Call this after AllowKeyUpEvents
  157.     }
  158.     else
  159.     {
  160.         CantRunOnThisMachine();
  161.     }
  162. }
  163.  
  164.  
  165. ///--------------------------------------------------------------------------------------
  166. // CreateSpriteWorld
  167. ///--------------------------------------------------------------------------------------
  168.  
  169. void    CreateSpriteWorld( void )
  170. {
  171.     Rect        offscreenRect, worldRect, windRect;
  172.     RgnHandle    mBarUpdateRgn;
  173.     OSErr        err;
  174.     
  175.     gWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  176.     
  177.     if (gWindowP != NULL)
  178.     {
  179.         if (kFullScreenWindow == true)
  180.         {
  181.                 // Fill screen, but no larger than 640x480
  182.             SizeWindow(gWindowP, SW_MIN(640, qd.screenBits.bounds.right), 
  183.                     SW_MIN(480, qd.screenBits.bounds.bottom), false);
  184.             MoveWindow(gWindowP, 0, 0, false);
  185.         }
  186.         
  187.             // Center window in screen
  188.         windRect = gWindowP->portRect;
  189.         CenterRect(&windRect, &qd.screenBits.bounds);
  190.         
  191.             // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  192.         windRect.left = windRect.left>>2<<2;
  193.         
  194.         MoveWindow(gWindowP, windRect.left, windRect.top, false);
  195.         
  196.         ShowWindow(gWindowP);
  197.         SetPort(gWindowP);
  198.         mBarUpdateRgn = SWHideMenuBar(gWindowP); // Must be done *after* showing window!
  199.         EraseRgn(mBarUpdateRgn);
  200.         
  201.         if (kInterlacedMode)
  202.             PaintRect(&gWindowP->portRect);    // Blacken window for Interlaced mode
  203.     }
  204.     else
  205.         CantFindResource();
  206.     
  207.     
  208.     err = SWEnterSpriteWorld();
  209.     FatalError(err);
  210.     
  211.     
  212.     worldRect = gWindowP->portRect;
  213.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  214.     
  215.         // Since our circular world must be evenly divisible by our offscreen area...
  216.     SetRect(&offscreenRect, 0, 0, 640, 480);
  217.     
  218.         // Create the scrolling sprite world
  219.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  220.             &worldRect, &offscreenRect, 0);
  221.     FatalError(err);
  222.     
  223.         // Create the sprite layers
  224.     err = SWCreateSpriteLayer(&gBallSpriteLayerP);        
  225.     FatalError(err);
  226.     err = SWCreateSpriteLayer(&gBottomSpriteLayerP);
  227.     FatalError(err);
  228.     err = SWCreateSpriteLayer(&gTopSpriteLayerP);
  229.     FatalError(err);
  230.     err = SWCreateSpriteLayer(&gMeterSpriteLayerP);
  231.     FatalError(err);
  232.     
  233.         // Add them to the world
  234.     SWAddSpriteLayer(gSpriteWorldP, gBallSpriteLayerP);        // Bottom
  235.     SWAddSpriteLayer(gSpriteWorldP, gBottomSpriteLayerP);    // Middle
  236.     SWAddSpriteLayer(gSpriteWorldP, gTopSpriteLayerP);        // Middle
  237.     SWAddSpriteLayer(gSpriteWorldP, gMeterSpriteLayerP);    // Top
  238.     
  239.     SWSetSpriteLayerUnderTileLayer(gBallSpriteLayerP, 0);
  240.     SWSetSpriteLayerUnderTileLayer(gBottomSpriteLayerP, 0);
  241.     
  242.         // Determine what DrawProcs to use
  243.     if (gSpriteWorldP->pixelDepth == 8)        // 256 colors
  244.     {
  245.         if (kInterlacedMode)
  246.         {
  247.             gSpriteDrawProc = BP8BitInterlacedMaskDrawProc;
  248.             gScreenDrawProc = BP8BitInterlacedRectDrawProc;
  249.             gDoubleRectDrawProc = BP8BitInterlacedDoubleRectDrawProc;
  250.             SWSetPartialMaskDrawProc(gSpriteWorldP, BP8BitInterlacedPartialMaskDrawProc);
  251.         }
  252.         else
  253.         {
  254.             gSpriteDrawProc = BlitPixie8BitMaskDrawProc;
  255.             gScreenDrawProc = SWStdWorldDrawProc;
  256.             gDoubleRectDrawProc = BlitPixie8BitDoubleRectDrawProc;
  257.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixie8BitPartialMaskDrawProc);
  258.         }
  259.     }
  260.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )    // Not 256 colors
  261.     {
  262.             // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  263.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  264.         {
  265.             gSpriteDrawProc = BPAllBitInterlacedMaskDrawProc;
  266.             gScreenDrawProc = BPAllBitInterlacedRectDrawProc;
  267.             SWSetPartialMaskDrawProc(gSpriteWorldP, BPAllBitInterlacedPartialMaskDrawProc);
  268.             if (gSpriteWorldP->pixelDepth == 16)
  269.                 gDoubleRectDrawProc = BP16BitInterlacedDoubleRectDrawProc;
  270.         }
  271.         else
  272.         {
  273.             gSpriteDrawProc = BlitPixieAllBitMaskDrawProc;
  274.             gScreenDrawProc = BlitPixieAllBitRectDrawProc;
  275.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  276.             if (gSpriteWorldP->pixelDepth == 16)
  277.                 gDoubleRectDrawProc = BlitPixie16BitDoubleRectDrawProc;
  278.         }
  279.     }
  280.     else
  281.     {
  282.         gSpriteDrawProc = SWStdSpriteDrawProc;
  283.         gScreenDrawProc = SWStdWorldDrawProc;
  284.         gDoubleRectDrawProc = NULL;
  285.     }
  286. }
  287.     
  288.     
  289. ///--------------------------------------------------------------------------------------
  290. // SetUpTiling
  291. ///--------------------------------------------------------------------------------------
  292.  
  293. void    SetUpTiling( void )    
  294. {
  295.     short        resIDOffset;
  296.     short        row, col;
  297.     OSErr        err;
  298.  
  299.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  300.     FatalError(err);
  301.     
  302.     err = SWCreateTileMap(&gTileMapStructP, kTileMapRows, kTileMapCols);
  303.     FatalError(err);
  304.     
  305.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  306.     gTileMap = gTileMapStructP->tileMap;
  307.  
  308.         // Determine whether to load B&W or color graphics
  309.     if (gSpriteWorldP->pixelDepth <= 2)
  310.         resIDOffset = kBWPictResIDOffset;
  311.     else
  312.         resIDOffset = 0;
  313.  
  314.         // Load first set of tiles
  315.     err = SWLoadTilesFromPictResource(
  316.         gSpriteWorldP, 
  317.         kWallTile,                // startTileID 
  318.         kLastDiamondTile,        // endTileID
  319.         200 + resIDOffset,        // pictResID
  320.         0,                        // maskResID
  321.         kNoMask,                // maskType
  322.         1,                        // horizBorderWidth
  323.         1);                        // vertBorderHeight
  324.     FatalError(err);
  325.     
  326.         // Load masked set of tiles
  327.     err = SWLoadTilesFromPictResource(
  328.         gSpriteWorldP, 
  329.         kTunnelTile1,            // startTileID 
  330.         kWireTile2,                // endTileID
  331.         201 + resIDOffset,        // pictResID
  332.         401,                    // maskResID
  333.         kFatMask,                // maskType
  334.         1,                        // horizBorderWidth
  335.         1);                        // vertBorderHeight
  336.     FatalError(err);
  337.  
  338.     
  339.         // Set up tileMap
  340.     for (row = 0; row < kTileMapRows; row++)
  341.     {
  342.         for (col = 0; col < kTileMapCols; col++)
  343.         {
  344.             if (row == 0 || col == 0 || row == kTileMapRows-1 || col == kTileMapCols-1)
  345.                 gTileMap[row][col] = kWallTile;
  346.             else if (row > kTileMapRows / 2)
  347.                 gTileMap[row][col] = kWireTile1;
  348.             else if ((row/kDiamondSpace)*kDiamondSpace == row && 
  349.                      (col/kDiamondSpace)*kDiamondSpace == col)
  350.             {
  351.                 gTileMap[row][col] = kDiamondTile;
  352.                 gNumDiamondsInMap++;
  353.             }
  354.             else
  355.                 gTileMap[row][col] = kGrassTile;
  356.         }
  357.     }
  358.     
  359.  
  360.         // Add tunnel to tileMap
  361.     row = kTileMapRows / 2;
  362.  
  363.     for (col = 1; col < kTileMapCols-1; col += 2)
  364.     {
  365.         gTileMap[row][col] = kTunnelTile1;
  366.         gTileMap[row][col+1] = kTunnelTile2;
  367.         gTileMap[row+1][col] = kTunnelTile4;
  368.         gTileMap[row+1][col+1] = kTunnelTile5;
  369.     }
  370. }
  371.  
  372.  
  373. ///--------------------------------------------------------------------------------------
  374. // CreateMainBallSprite
  375. ///--------------------------------------------------------------------------------------
  376.  
  377. void    CreateMainBallSprite( void )
  378. {
  379.     OSErr    err;
  380.     
  381.         // Create the ball sprite
  382.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSimpleSpriteP, NULL, 
  383.             128, 1, kFatMask);    
  384.     FatalError(err);
  385.     
  386.         // Set up the ball sprite
  387.     SWAddSprite(gBallSpriteLayerP, gSimpleSpriteP);
  388.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  389.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  390.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  391.     SWSetSpriteDrawProc(gSimpleSpriteP, gSpriteDrawProc);
  392. }
  393.  
  394.  
  395. ///--------------------------------------------------------------------------------------
  396. // CreateDiamondMeterSprite
  397. ///--------------------------------------------------------------------------------------
  398.  
  399. void    CreateDiamondMeterSprite( void )
  400. {
  401.     short        spriteResID;
  402.     OSErr        err;
  403.     
  404.         // Calculate resource ID for diamond meter sprite
  405.     if (gSpriteWorldP->pixelDepth <= 2)
  406.         spriteResID = 302;
  407.     else
  408.         spriteResID = 202;
  409.     
  410.         // Create the diamond meter sprite
  411.     err = SWCreateSpriteFromPictResource(gSpriteWorldP,
  412.                 &gDiamondMeterSpriteP, 
  413.                 NULL,            // pointer to memory for sprite
  414.                 spriteResID,     // picture resource id
  415.                 402,            // mask resource id
  416.                 1,                 // max frames
  417.                 kPixelMask);    // mask type
  418.     FatalError(err);
  419.     
  420.     SWAddSprite(gMeterSpriteLayerP, gDiamondMeterSpriteP);
  421.     SWSetSpriteDrawProc(gDiamondMeterSpriteP, gSpriteDrawProc);
  422. }
  423.  
  424.  
  425. ///--------------------------------------------------------------------------------------
  426. // CreateBallSprites
  427. ///--------------------------------------------------------------------------------------
  428.  
  429. void    CreateBallSprites( void )
  430. {
  431.     SpritePtr            simpleSpriteP;
  432.     short                spriteNum;
  433.     Rect                moveBoundsRect;
  434.     OSErr                err;
  435.     
  436.         // Create the first sprite
  437.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSpriteArray[0], NULL, 
  438.             200, 2, kFatMask);    
  439.     FatalError(err);
  440.     
  441.         // Save the sprite's width. This info used when scaling later.
  442.     gScaledWidth = gSpriteArray[0]->destFrameRect.right - gSpriteArray[0]->destFrameRect.left;
  443.     gScaledHeight = gSpriteArray[0]->destFrameRect.bottom - gSpriteArray[0]->destFrameRect.top;
  444.     gOriginalWidth = gScaledWidth;
  445.     gOriginalHeight = gScaledHeight;
  446.     
  447.         // clone the rest of the sprites off the first one
  448.     for (spriteNum = 1; spriteNum < kNumSprites; spriteNum++)
  449.     {
  450.         err = SWCloneSprite(gSpriteArray[0], &gSpriteArray[spriteNum], NULL);
  451.         FatalError(err);
  452.     }
  453.     
  454.         // Calculate size of virtual world
  455.     SetRect(&moveBoundsRect, 0, 0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  456.     
  457.     
  458.         // Set up the sprites in random locations with random deltas
  459.     for (spriteNum = 0; spriteNum < kNumSprites; spriteNum++)
  460.     {
  461.         simpleSpriteP = gSpriteArray[spriteNum];
  462.         
  463.         if (GetRandom(0,1) == 0)
  464.             SWAddSprite(gBottomSpriteLayerP, gSpriteArray[spriteNum]);    // Add above wire tiles
  465.         else
  466.             SWAddSprite(gTopSpriteLayerP, gSpriteArray[spriteNum]);        // Add below wire tiles
  467.         
  468.         SWSetSpriteMoveProc(simpleSpriteP, BallSpriteMoveProc);
  469.         SWSetSpriteDrawProc(simpleSpriteP, gSpriteDrawProc);
  470.         SWSetSpriteCollideProc(simpleSpriteP, BallSpriteCollideProc);
  471.         
  472.         SWSetSpriteLocation(simpleSpriteP, 
  473.                 GetRandom(0, moveBoundsRect.right), 
  474.                 GetRandom(0, moveBoundsRect.bottom) );
  475.         
  476.         do
  477.         {
  478.             SWSetSpriteMoveDelta(simpleSpriteP, 
  479.                 GetRandom(-kMaxSpriteMoveDelta, kMaxSpriteMoveDelta), 
  480.                 GetRandom(-kMaxSpriteMoveDelta, kMaxSpriteMoveDelta));
  481.         } while (simpleSpriteP->horizMoveDelta == 0 || simpleSpriteP->vertMoveDelta == 0);
  482.     }    
  483. }
  484.  
  485.  
  486. ///--------------------------------------------------------------------------------------
  487. // SetUpAnimation
  488. ///--------------------------------------------------------------------------------------
  489.  
  490. void    SetUpAnimation( void )
  491. {
  492.     Rect        moveBoundsRect;
  493.     
  494.     SWLockSpriteWorld(gSpriteWorldP);
  495.     
  496.         // Set up data used by the SmoothScrollingWorldMoveProc
  497.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  498.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  499.     
  500.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  501.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  502.     SWSetCleanUpSpriteWorld(gSpriteWorldP);
  503.     
  504.         // movement boundary = size of tileMap
  505.     SetRect(&moveBoundsRect, 0,0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  506.     
  507.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  508.     SWSetScrollingWorldMoveProc(gSpriteWorldP, KeyScrollRectMoveProc, NULL);
  509.     
  510.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  511.     
  512.         // Set starting position of diamond meter sprite
  513.     DiamondMeterSpriteMoveProc(gDiamondMeterSpriteP);
  514.  
  515.     SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, gScreenDrawProc);
  516.     SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, gScreenDrawProc);
  517.     SWSetDoubleRectDrawProc(gSpriteWorldP, gDoubleRectDrawProc);    
  518.     
  519.         // Make sure CopyBits, if used, doesn't try to colorize things
  520.     SWSetPortToWindow(gSpriteWorldP);
  521.     ForeColor(blackColor);
  522.     BackColor(whiteColor);
  523.     
  524.     SWDrawTilesInCircularBackground(gSpriteWorldP);
  525.     SWUpdateCircularSpriteWorld(gSpriteWorldP);
  526.     
  527.     if (kDoZoomOutIntro)
  528.         DoZoomOut();
  529. }
  530.  
  531.  
  532. ///--------------------------------------------------------------------------------------
  533. //  DoZoomOut - a special effect
  534. ///--------------------------------------------------------------------------------------
  535.  
  536. void    DoZoomOut( void )
  537. {
  538.     Rect            srcRect = gSpriteWorldP->backRect;
  539.     Rect            myBackRect;
  540.     DrawProcPtr        drawProcP;
  541.     short            newWidth, newHeight, worldWidth, worldHeight;
  542.     double            percent, increase;
  543.     
  544.         // Determine what DrawProc to use
  545.     if (gSpriteWorldP->pixelDepth == 8)
  546.         drawProcP = BlitPixie8BitScaledRectDrawProc;
  547.     else if (gSpriteWorldP->pixelDepth == 16)
  548.         drawProcP = BlitPixie16BitScaledRectDrawProc;
  549.     else
  550.         drawProcP = SWStdWorldDrawProc;
  551.     
  552.     worldWidth = SW_RECT_WIDTH(gSpriteWorldP->windRect);
  553.     worldHeight = SW_RECT_HEIGHT(gSpriteWorldP->windRect);
  554.     myBackRect = gSpriteWorldP->windRect;
  555.     OffsetRect(&myBackRect, -myBackRect.left, -myBackRect.top);
  556.     
  557.     increase = 1;
  558.     for (percent = 2; percent <= 100 && !Button(); percent += increase)
  559.     {    
  560.         increase += .1;    // This makes the scaling go faster the closer we get to the end
  561.         
  562.             // Look in SWCommonHeaders.h to see what these macros do
  563.         newWidth = ((double)worldWidth * percent) / 100;
  564.         newHeight = ((double)worldHeight * percent) / 100;
  565.         
  566.         SW_SET_RECT(srcRect, 0, 0, newWidth, newHeight);
  567.         CenterRect(&srcRect, &myBackRect);
  568.         
  569.         (*drawProcP)(gSpriteWorldP->workFrameP, gSpriteWorldP->windowFrameP,
  570.             &srcRect, &gSpriteWorldP->windRect);
  571.     }
  572. }
  573.  
  574.  
  575. ///--------------------------------------------------------------------------------------
  576. //  RunAnimation
  577. ///--------------------------------------------------------------------------------------
  578.  
  579. void    RunAnimation( void )
  580. {
  581.     unsigned long        frames;
  582.         
  583.     frames = 0;
  584.     StartTimer();
  585.  
  586.     FatalError( SWStickyError() ); // Make sure no errors got past us during setup
  587.  
  588.     while (!Button())
  589.     {
  590.         SWProcessCircularSpriteWorld(gSpriteWorldP);
  591.         
  592.             // We call this in case the Control Strip or something changes our window's visRgn
  593.         KeepMenuBarHidden(gWindowP);
  594.  
  595.             // Move diamond meter sprite to new visScrollRect location
  596.         DiamondMeterSpriteMoveProc(gDiamondMeterSpriteP);
  597.         
  598.             // Check for collisions with the ball sprites
  599.         SWCollideCircularSpriteLayer(gSpriteWorldP, gTopSpriteLayerP, gTopSpriteLayerP);
  600.         SWCollideCircularSpriteLayer(gSpriteWorldP, gBottomSpriteLayerP, gBottomSpriteLayerP);
  601.         SWCollideCircularSpriteLayer(gSpriteWorldP, gBottomSpriteLayerP, gTopSpriteLayerP);
  602.         
  603.             // Make sure no errors occurred during a MoveProc, etc.
  604.         FatalError( SWStickyError() );
  605.     
  606.         SWAnimateCircularSpriteWorld(gSpriteWorldP);
  607.         
  608.         if (gSpriteWorldP->frameHasOccurred)
  609.             frames++;
  610.     }
  611.     
  612.     
  613.     ShowResults(frames);
  614.     SWShowMenuBar(gWindowP);
  615. }
  616.  
  617.  
  618. ///--------------------------------------------------------------------------------------
  619. //  ShutDown (clean up and dispose of the SpriteWorld)
  620. ///--------------------------------------------------------------------------------------
  621.  
  622. void    ShutDown( void )
  623. {
  624.     SWDisposeSpriteWorld(&gSpriteWorldP);
  625.     SWExitSpriteWorld();
  626.     
  627.     FlushEvents(everyEvent, 0);
  628.     ShowCursor();
  629. }
  630.  
  631.  
  632. ///--------------------------------------------------------------------------------------
  633. //  TileChangeProc
  634. ///--------------------------------------------------------------------------------------
  635.  
  636. SW_FUNC void TileChangeProc(
  637.     SpriteWorldPtr spriteWorldP)
  638. {
  639.     short            curImage;
  640.     static short    wallDelay = 0, diamondDelay = 0;
  641.     static short    oldTicks = 0;
  642.     short            ticksPassed, ticks;
  643.     
  644.         // Initialize oldTicks the first time this function is called
  645.     if (oldTicks == 0)
  646.         oldTicks = TickCount();
  647.     
  648.     ticks = TickCount();
  649.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  650.     oldTicks = ticks;
  651.     
  652.         // kWallTile
  653.     wallDelay += ticksPassed;
  654.     if (wallDelay >= kWallFrameRate)
  655.     {
  656.         curImage = spriteWorldP->curTileImage[kWallTile];
  657.         if (curImage < kLastWallTile)
  658.             curImage++;
  659.         else
  660.             curImage = kWallTile;
  661.         
  662.         SWChangeCircularTileImage(spriteWorldP, kWallTile, curImage);
  663.         wallDelay = 0;
  664.     }
  665.     
  666.     
  667.         // kDiamondTile
  668.     diamondDelay += ticksPassed;
  669.     if (diamondDelay >= kDiamondFrameRate)
  670.     {
  671.         curImage = spriteWorldP->curTileImage[kDiamondTile];
  672.         if (curImage < kLastDiamondTile)
  673.             curImage++;
  674.         else
  675.             curImage = kDiamondTile;
  676.         
  677.         SWChangeCircularTileImage(spriteWorldP, kDiamondTile, curImage);
  678.         diamondDelay = 0;
  679.     }
  680. }
  681.  
  682.  
  683. ///--------------------------------------------------------------------------------------
  684. //  KeySpriteMoveProc
  685. ///--------------------------------------------------------------------------------------
  686.  
  687. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  688. {
  689.     short    row, col;
  690.     short    rowDelta, colDelta;
  691.     short    tile;
  692.     
  693.     UpdateKeys();    // Put the latest key values in the keys structure
  694.     
  695.     
  696.     row = srcSpriteP->destFrameRect.top / kTileHeight;
  697.     col = srcSpriteP->destFrameRect.left / kTileWidth;
  698.  
  699.     if (row * kTileHeight == srcSpriteP->destFrameRect.top &&
  700.         col * kTileWidth == srcSpriteP->destFrameRect.left)
  701.     {
  702.         tile = gTileMap[row][col];
  703.         
  704.             // Leave black trail behind sprite
  705.         if (tile == kGrassTile || tile == kDiamondTile)
  706.             SWDrawCircularTile(gSpriteWorldP, 0, row, col, kBlackTile);
  707.         else if (tile == kTunnelTile2 || tile == kTunnelTile5 || tile == kWireTile1)
  708.             SWDrawCircularTile(gSpriteWorldP, 0, row, col, tile+1);
  709.             
  710.         if (tile == kDiamondTile)
  711.         {
  712.             gNumDiamonds++;            // Increase number of diamonds sprite has collected
  713.             UpdateDiamondMeter();    // Update meter
  714.         }
  715.         
  716.  
  717.         rowDelta = 0;
  718.         colDelta = 0;
  719.         
  720.         if (gBallKeys.left)
  721.             colDelta = -1;
  722.         else if (gBallKeys.right)
  723.             colDelta = 1;
  724.         else if (gBallKeys.up)
  725.             rowDelta = -1;
  726.         else if (gBallKeys.down)
  727.             rowDelta = 1;
  728.         
  729.                 
  730.         
  731.         tile = gTileMap[row + rowDelta][col + colDelta];
  732.         
  733.         if (tile != kWallTile && tile != kTunnelTile1 && tile != kTunnelTile4)
  734.         {
  735.             srcSpriteP->vertMoveDelta = rowDelta * kSpriteMoveDelta;
  736.             srcSpriteP->horizMoveDelta = colDelta * kSpriteMoveDelta;
  737.         }
  738.         else
  739.         {
  740.             srcSpriteP->vertMoveDelta = 0;
  741.             srcSpriteP->horizMoveDelta = 0;
  742.         }
  743.     }
  744.     
  745.     SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  746. }
  747.  
  748.  
  749. ///--------------------------------------------------------------------------------------
  750. //  DiamondMeterSpriteMoveProc - not installed as a MoveProc, but called directly
  751. ///--------------------------------------------------------------------------------------
  752.  
  753. SW_FUNC void DiamondMeterSpriteMoveProc(SpritePtr srcSpriteP)
  754. {
  755.         // Move sprite to top-left corner of current visScrollRect location
  756.     SWMoveSprite(srcSpriteP, 
  757.         gSpriteWorldP->visScrollRect.left + 10, 
  758.         gSpriteWorldP->visScrollRect.top + 10);
  759. }
  760.  
  761. ///--------------------------------------------------------------------------------------
  762. //    BallSpriteMoveProc - used to move all the randomly moving balls
  763. ///--------------------------------------------------------------------------------------
  764.  
  765. SW_FUNC void BallSpriteMoveProc(SpritePtr srcSpriteP)
  766. {
  767.     SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  768.     
  769.         // Reset sprite back to normal frame (in case it had a collision and was changed)
  770.     if (srcSpriteP->curFrameIndex != 0)
  771.         SWSetCurrentFrameIndex(srcSpriteP, 0);
  772. }
  773.  
  774.  
  775. ///--------------------------------------------------------------------------------------
  776. //    BallSpriteCollideProc
  777. ///--------------------------------------------------------------------------------------
  778.  
  779. SW_FUNC void BallSpriteCollideProc(SpritePtr srcSpriteP, SpritePtr dstSpriteP, Rect *sectRect)
  780. {
  781.     #pragma    unused(sectRect)    // Tell CodeWarrior this variable is unused
  782.     
  783.         // Turn the sprites whiter while they are colliding
  784.     if (srcSpriteP->curFrameIndex != 1)
  785.         SWSetCurrentFrameIndex(srcSpriteP, 1);
  786.     
  787.     if (dstSpriteP->curFrameIndex != 1)
  788.         SWSetCurrentFrameIndex(dstSpriteP, 1);
  789. }
  790.  
  791.  
  792. ///--------------------------------------------------------------------------------------
  793. //  UpdateDiamondMeter - change the meter Sprite's image and mask
  794. ///--------------------------------------------------------------------------------------
  795.  
  796. SW_FUNC void UpdateDiamondMeter( void )
  797. {
  798.     double    percent;
  799.     Rect    meterRect;
  800.     
  801.     percent = (double)gNumDiamonds / gNumDiamondsInMap;
  802.     
  803.         // 108 = length of meter; 17 = offset from start of meter
  804.     SetRect(&meterRect, 17, 2, (108 * percent) + 17, 14);
  805.     
  806.     
  807.         // Set port to our sprite's framePort GWorld
  808.     SetGWorld(gDiamondMeterSpriteP->curFrameP->framePort, nil);
  809.     
  810.     ForeColor(magentaColor);
  811.     PaintRect(&meterRect);
  812.     
  813.         // IMPORTANT: Set the color back when done! (In case CopyBits is used later)
  814.     ForeColor(blackColor);
  815.     
  816.     
  817.         // Set port to our sprite's pixel mask GWorld
  818.     SetGWorld(gDiamondMeterSpriteP->curFrameP->maskPort, nil);
  819.     
  820.         // Mask image is inverted when in 8-bit or less
  821.     if (gSpriteWorldP->pixelDepth <= 8)
  822.         ForeColor(whiteColor);
  823.     else
  824.         ForeColor(blackColor);
  825.     
  826.     PaintRect(&meterRect);
  827.     ForeColor(blackColor);
  828.     
  829.     
  830.         // Set sprite to be redrawn, since we've changed its image
  831.     gDiamondMeterSpriteP->needsToBeDrawn = true;
  832. }
  833.  
  834.  
  835. ///--------------------------------------------------------------------------------------
  836. //  KeyScrollRectMoveProc
  837. ///--------------------------------------------------------------------------------------
  838.  
  839. SW_FUNC void    KeyScrollRectMoveProc(
  840.     SpriteWorldPtr spriteWorldP,
  841.     SpritePtr followSpriteP)
  842. {    
  843.     #pragma    unused(followSpriteP)    // Tell CodeWarrior this variable is unused
  844.     
  845.     UpdateKeys();
  846.     
  847.     spriteWorldP->vertScrollDelta = (gScrollKeys.down - gScrollKeys.up) * kScrollSpeed;        
  848.     spriteWorldP->horizScrollDelta = (gScrollKeys.right - gScrollKeys.left) * kScrollSpeed;
  849. }
  850.  
  851.  
  852. ///--------------------------------------------------------------------------------------
  853. //  UpdateKeys (Put the latest key values in the keys structure)
  854. ///--------------------------------------------------------------------------------------
  855.  
  856. void    UpdateKeys( void )
  857. {
  858.     EventRecord        event;
  859.     short            theKey;
  860.     Boolean            isDown;
  861.     
  862.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  863.     {
  864.         theKey = (event.message & keyCodeMask) >> 8;
  865.         isDown = (event.what != keyUp);
  866.         
  867.         if (theKey == kLeftArrowKey)
  868.             gBallKeys.left = isDown;
  869.         else if (theKey == kRightArrowKey)
  870.             gBallKeys.right = isDown;
  871.         else if (theKey == kDownArrowKey)
  872.             gBallKeys.down = isDown;
  873.         else if (theKey == kUpArrowKey)
  874.             gBallKeys.up = isDown;
  875.         
  876.         if (theKey == kLeftKeyPad)
  877.             gScrollKeys.left = isDown;
  878.         else if (theKey == kRightKeyPad)
  879.             gScrollKeys.right = isDown;
  880.         else if (theKey == kDownKeyPad)
  881.             gScrollKeys.down = isDown;
  882.         else if (theKey == kUpKeyPad)
  883.             gScrollKeys.up = isDown;
  884.         
  885.         if (theKey == kMinusKey)
  886.             gMinusKeyIsDown = isDown;
  887.         else if (theKey == kPlusKey)
  888.             gPlusKeyIsDown = isDown;
  889.         else if (theKey == kReturnKey)
  890.             gReturnKeyIsDown = isDown;
  891.     }
  892.     
  893.     UpdateScaledSprites();
  894. }
  895.  
  896.  
  897. ///--------------------------------------------------------------------------------------
  898. //  UpdateScaledSprites
  899. ///--------------------------------------------------------------------------------------
  900.  
  901. void    UpdateScaledSprites( void )
  902. {
  903.     short    offset;
  904.     
  905.     if (gMinusKeyIsDown)
  906.     {
  907.         if (gScaledWidth > 5 && gScaledHeight > 5)
  908.         {
  909.             gScaledWidth -= 2;
  910.             gScaledHeight -= 2;
  911.             ScaleSprites(1);
  912.         }
  913.     }
  914.     
  915.     if (gPlusKeyIsDown)
  916.     {
  917.         gScaledWidth += 2;
  918.         gScaledHeight += 2;
  919.         ScaleSprites(-1);
  920.     }
  921.     
  922.     if (gReturnKeyIsDown)
  923.     {
  924.         offset = gScaledWidth - gOriginalWidth;
  925.         gScaledWidth = gOriginalWidth;
  926.         gScaledHeight = gOriginalHeight;
  927.         ScaleSprites( offset / 2 );
  928.     }
  929. }
  930.  
  931.  
  932. ///--------------------------------------------------------------------------------------
  933. //  ScaleSprites
  934. ///--------------------------------------------------------------------------------------
  935.  
  936. void    ScaleSprites( short spriteOffset )
  937. {
  938.     SpritePtr curSpriteP;
  939.     
  940.     if (gSpriteWorldP->pixelDepth < 8 || gSpriteWorldP->pixelDepth > 16)
  941.         return;
  942.     
  943.         // Update all sprites in gTopSpriteLayer
  944.     curSpriteP = SWGetNextSprite(gTopSpriteLayerP, NULL);
  945.     while (curSpriteP != NULL)
  946.     {
  947.         SWSetSpriteScaledSize(curSpriteP, gScaledWidth, gScaledHeight);
  948.         SWOffsetSprite(curSpriteP, spriteOffset, spriteOffset);
  949.         curSpriteP = SWGetNextSprite(gTopSpriteLayerP, curSpriteP);
  950.     }
  951.     
  952.         // Update all sprites in gBottomSpriteLayer
  953.     curSpriteP = SWGetNextSprite(gBottomSpriteLayerP, NULL);
  954.     while (curSpriteP != NULL)
  955.     {
  956.         SWSetSpriteScaledSize(curSpriteP, gScaledWidth, gScaledHeight);
  957.         SWOffsetSprite(curSpriteP, spriteOffset, spriteOffset);
  958.         curSpriteP = SWGetNextSprite(gBottomSpriteLayerP, curSpriteP);
  959.     }
  960. }